home *** CD-ROM | disk | FTP | other *** search
-
- /* Patch.m Peter Wickersham
- *
- * Methods for Patch class.
- *
- */
-
- #import "../Stone3DAPI/Stone3D.h"
-
- #import "Patch.h"
- #import "../ControlPoint.bproj/ControlPoint.h"
- #import <ri/ri.h>
-
- #define X0 -1.0
- #define X1 -0.33
- #define X2 0.33
- #define X3 1.0
- #define Y0 -0.7
- #define Y1 -0.1
- #define Y2 0.1
- #define Y3 0.7
- #define Z0 -1.0
- #define Z1 -0.33
- #define Z2 0.33
- #define Z3 1.0
-
- #define BEZIER 0
- #define HERMITE 1
- #define BSPLINE 2
- #define CATMULLROM 3
-
-
- @implementation Patch
-
- // The init method has the same overall implications as it usually does in
- // instance initialization with the added bonus of knowing that your shape
- // will added into the worldShape hierarchy according to the actions of the
- // user. Therefore, you can create a small little hierarchy of your own with
- // the knowledge that it be just fit right in.
- // In Patch, I create the standard Patch shape the appears in The RenderMan
- // Companion.
- - init
- {
- RtFloat pts[16][3] = {
- { X0, Y0, Z0}, { X1, Y2, Z0}, { X2, Y1, Z0}, { X3, Y3, Z0},
- { X0, Y1, Z1}, { X1, Y2, Z1}, { X2, Y1, Z1}, { X3, Y2, Z1},
- { X0, Y1, Z2}, { X1, Y2, Z2}, { X2, Y1, Z2}, { X3, Y2, Z2},
- { X0, Y0, Z3}, { X1, Y2, Z3}, { X2, Y1, Z3}, { X3, Y3, Z3}};
- id temp, lastShape;
- int i;
-
- // First I let Shape perform any inits that it might need to.
- [super init];
-
- // Then I create my List of control points, which are subclassed Shapes
- // as well, and give them their initial translations. Finally I add them
- // in the hierarchy under Patch. In order to set up the sub hierarchy
- // correctly, we need to add the first control point as a descendent of
- // self(Patch) and then add all subsequent point shape objects as peers
- // to the last added point.
- controlPts = [[List allocFromZone:[self zone]] initCount:16];
- temp = [[ControlPoint allocFromZone:[self zone]] init];
- [temp translateTo:pts[0][0] :pts[0][1] :pts[0][2]];
- [temp linkAncestor:self];
- [self linkDescendant:temp];
- [controlPts addObject:temp];
- for (i=1; i<16; i++) {
- lastShape = temp;
- temp = [[ControlPoint allocFromZone:[self zone]] init];
- [temp translateTo:pts[i][0] :pts[i][1] :pts[i][2]];
- [lastShape linkPeer:temp];
- [controlPts addObject:temp];
- }
-
- // Finally, I set the default basis matrices and step sizes.
- // The step sizes for a singular patch is always 3 and does not
- // really matter unless it is a mesh.
- uBasis = BEZIER; bcopy(&RiBezierBasis,&theUBasis,sizeof(RtBasis));
- vBasis = BEZIER; bcopy(&RiBezierBasis,&theVBasis,sizeof(RtBasis));
- uStep = 3;
- vStep = 3;
- showCtlPoints = YES;
- showHull = NO;
-
- // The X min and max
- boundingBox[0] = 999; boundingBox[1] = -999;
-
- // The Y min and max
- boundingBox[2] = 999; boundingBox[3] = -999;
-
- // The Z min and max
- boundingBox[4] = 999; boundingBox[5] = -999;
-
- return self;
- }
-
-
- // The following methods are for querying and setting various instance
- // variables. These variables are generally going to be accessed through
- // an inspector panel that is installed concurrently with this class by
- // the 3DReality class management facilities. Therefore, if you want to
- // allow the user to set characteristics of your shape, then you must provide
- // an inspector of the name <shapeClassName>Inspector with interface objects
- // for tweaking parameters.
-
- - (BOOL) hullVisible
- {
- return showHull;
- }
-
- - setHullVisible:(BOOL) flag
- {
- showHull = flag;
- return self;
- }
-
- - (BOOL)controlVisible
- {
- return showCtlPoints;
- }
-
- - setControlVisible:(BOOL)flag
- {
- int i, max;
- id *clist;
-
- showCtlPoints = flag;
- for (i=0, max = [controlPts count],
- clist=NX_ADDRESS(controlPts);i<max;i++) {
- [clist[i] setVisible:flag];
- }
- return self;
- }
-
- - (int)uBasis
- {
- return uBasis;
- }
-
- - setUBasis:(int)theU
- {
- uBasis = theU;
- switch (uBasis) {
- case BEZIER: bcopy(&RiBezierBasis,&theUBasis,sizeof(RtBasis));
- break;
- case HERMITE: bcopy(&RiHermiteBasis,&theUBasis,sizeof(RtBasis));
- break;
- case BSPLINE: bcopy(&RiBSplineBasis,&theUBasis,sizeof(RtBasis));
- break;
- case CATMULLROM: bcopy(&RiCatmullRomBasis,&theUBasis,sizeof(RtBasis));
- break;
- default: bcopy(&RiBezierBasis,&theUBasis,sizeof(RtBasis));
- }
- return self;
- }
-
- - (int)vBasis
- {
- return vBasis;
- }
-
- - setVBasis:(int)theV
- {
- vBasis = theV;
- switch (vBasis) {
- case BEZIER: bcopy(&RiBezierBasis,&theVBasis,sizeof(RtBasis));
- break;
- case HERMITE: bcopy(&RiHermiteBasis,&theVBasis,sizeof(RtBasis));
- break;
- case BSPLINE: bcopy(&RiBSplineBasis,&theVBasis,sizeof(RtBasis));
- break;
- case CATMULLROM: bcopy(&RiCatmullRomBasis,&theVBasis,sizeof(RtBasis));
- break;
- default: bcopy(&RiBezierBasis,&theVBasis,sizeof(RtBasis));
- }
- return self;
- }
-
-
- // In order to provide selection capablity we must override Shapes instance
- // method calcBoundingBox.
- - calcBoundingBox
- {
- int i, max; // index variables
- id *clist; // Address of control point list
- RtFloat pt[3];
-
- for (i=0, max = [controlPts count],
- clist=NX_ADDRESS(controlPts);i<max;i++) {
- [clist[i] trans:&pt[0]];
- if (pt[0] < boundingBox[0]) boundingBox[0] = pt[0];
- if (pt[0] > boundingBox[1]) boundingBox[1] = pt[0];
- if (pt[1] < boundingBox[2]) boundingBox[2] = pt[1];
- if (pt[1] > boundingBox[3]) boundingBox[3] = pt[1];
- if (pt[2] < boundingBox[4]) boundingBox[4] = pt[2];
- if (pt[2] > boundingBox[5]) boundingBox[5] = pt[2];
- }
- return self;
- }
-
-
- // doRenderSelf is the method where the rendering code is placed. Here we
- // just make normal RenderMan function calls for creating RIB code that gets
- // interpreted by either QRMAN or PRMAN depending on whether we are printing
- // or drawing the RIB code.
- - doRenderSelf: (Camera *) camera
- {
- int i, max; // index variables
- id *clist; // Address of control point list
- RtFloat tmppts[16][3]; // The current position of the control points
-
- // verts and nverst are for passing the vertex info to RiPointsPolygon
- // for the control hull.
- static RtInt verts[32] = {0,1,5,4,4,5,9,8,8,9,13,12,13,14,10,6,2,1,5,9,
- 2,3,7,6,6,7,11,10,14,15,11,10};
- static RtInt nverts[7] = {4,4,4,8,4,4,4};
-
- // First let our superclass Shape do its rendering code. This could
- // include shading and texturing calls.
- [super doRenderSelf:camera];
-
- // Then we get the current translation information from the control
- // points. This gives us their current positions in the Patch space.
- for (i=0, max = [controlPts count],
- clist=NX_ADDRESS(controlPts);i<max;i++) {
- [clist[i] trans:&tmppts[i][0]];
- }
-
- // Draw the control hull polygon if needed using RiPointsPolygon
- if (showHull) {
- RiPointsPolygons((RtInt)7,nverts,verts,RI_P,(RtPointer)tmppts,RI_NULL);
- }
-
- // Set the U and V basis matrices and then draw the patch using
- // RiPatch with the translations of the control points.
- RiBasis(theUBasis, (RtInt)uStep, theVBasis, (RtInt)vStep);
- RiPatch(RI_BICUBIC, RI_P, (RtPointer)tmppts, RI_NULL);
-
- return self;
- }
- @end
-